/*******************************************************************************
版权声明: Copyright(C) HT-Tech Co., Ltd. 2020-2021. All rights reserved.
文件名称: htprotocl.c
文件描述: 隧道协议接口定义
创 建 者: 陈位仅
创建时间: 2024年11月13日
修改历史:
1. 2024年11月13日   陈位仅      创建文件 
*******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>

#include "htmacro.h"
#include "htcfg.h"
#include "htprotocol.h"
#include "htacl.h"

// 封装终端认证请求包
int htprc_request(IN ht_cfg_t *pCfg, OUT char *pOut, OUT int *pLen)
{
    int len = 0;
    ht_head_t *pHead = NULL;            // 封装包头
    ht_auth_request_t *pAuth = NULL;    // 封装认证请求包

    // 参数校验
    if (NULL == pCfg || NULL == pOut || NULL == pLen) {
        return -1;
    }

    pHead = (void *)pOut;
    // 封装包头
    pHead->ht_version = htons(_HT_VERSION);
    pHead->ht_type = htons(_HT_TYPE_AUTH_REQUEST);

    // 封装认证请求包
    pAuth = (void *)pHead->ht_data;
    pAuth->ht_mode = pCfg->mode;

    // 封装认证请求包数据
    sprintf(pAuth->ht_data, "%s;%s;TYPE:%d", pCfg->username, pCfg->passwd, pCfg->type);

    // 计算包长度
    len = strlen(pAuth->ht_data) + sizeof(ht_auth_request_t) + sizeof(ht_head_t);
    pHead->ht_len = htons(len);

    // 返回包长度
    *pLen = len;

    return 0;
}

// 终端认证响应包解析
int htprc_respone(OUT char *pIN, IN int Len)
{
    int i = 0;
    int aclCnt = 0;     // 访问控制数量
    ht_head_t *pHead = NULL;            // 待解析包头指针
    ht_auth_response_t *pAuth = NULL;   // 待解析包体指针
    char aclType = 0;                   // ACL 类型
    char *pData = NULL;                 // ACL 数据指针

    // 获取包头指针
    pHead = (void *)pIN;
    pAuth = (void *)pHead->ht_data;

    // 认证结果检测
    if (0 != pAuth->ht_result) {
        return -1;
    }

    // 获取ACL
    aclCnt = ntohs(pAuth->ht_acl);
    pData = pAuth->ht_data;     // 第一条ACL
    aclType = *pData;           // 第一条ACL类型
    for ( ; i < aclCnt; i++) {
        switch (aclType)
        {
        case _HT_ACL_TYPE_IPv4:
        case _HT_ACL_TYPE_IPv6:
            // 添加ACL节点
            htacl_add(pData, sizeof(ht_acl_ip_t));
            // 获取下一个ACL数据
            pData += sizeof(ht_acl_ip_t);
            break;
        case _HT_ACL_TYPE_IPv4_Range:
        case _HT_ACL_TYPE_IPv6_Range:
            // 添加ACL节点
            htacl_add(pData, sizeof(ht_acl_range_t));
            // 获取下一个ACL数据
            pData += sizeof(ht_acl_range_t);
            break;
        case _HT_ACL_TYPE_IPv4_Subnet:
        case _HT_ACL_TYPE_IPv6_Subnet:
            // 添加ACL节点
            htacl_add(pData, sizeof(ht_acl_subnet_t));
            // 获取下一个ACL数据
            pData += sizeof(ht_acl_subnet_t);
            break;
        default:
            break;
        }
        aclType = *pData;
    }

    return 0;
}

// 配置推送包解析
int htprc_config(IN ht_cfg_t *pDCfg, IN char *pIN, IN int Len)
{
    int i = 0;
    int cfgCnt = 0;               // 配置项个数
    ht_head_t *pHead = NULL;      // 待解析包头指针
    ht_cfg_push_t *pCfg = NULL;   // 待解析配置项
    ht_cfg_item_t *pCmd = NULL;   // 配置项命令
    ht_cfg_item_t *pArg= NULL;    // 配置项命令参数
    void *pData = NULL;           // 待解析数据指针
    char cmd[128] = {0};          // 命令行参数

    // 参数合法性检测
    if (NULL == pDCfg || NULL == pIN) {
        return -1;
    }

    // 获取包头指针
    pHead = (void *)pIN;
    pCfg = (void *)pHead->ht_data;

    // 获取配置项个数
    cfgCnt = ntohs(pCfg->ht_cfg_cnt);
    pData = (void *)pCfg->ht_data;
    for ( ; i < cfgCnt; i++) {
        // 命令配置
        memset(cmd, 0, sizeof(cmd));
        pCmd = pData;
        pArg = (void *)((char *)pCmd->ht_item_data + ntohs(pCmd->ht_item_len));

        // 头两条命令为网络配置命令
        switch (i)
        {
        case 0:
            sprintf(cmd, "%s %s %s", pCmd->ht_item_data, pDCfg->tunnel, pArg->ht_item_data);
            break;
        case 1:
            sprintf(cmd, "%s %s dev %s", pCmd->ht_item_data, pArg->ht_item_data, pDCfg->tunnel);
            break;
        default:
            sprintf(cmd, "%s %s", pCmd->ht_item_data, pArg->ht_item_data);
            break;
        }

        // 执行命令
        // printf("%s\n", cmd);
        system(cmd);

        // 获取下一个配置项
        pData = (void *)((char *)pArg->ht_item_data + ntohs(pArg->ht_item_len));
    }

    return 0;
}


// 心跳报文封装
int htprc_heartbeat(OUT char *pOut, OUT int *pLen)
{
    int len = 0;
    ht_head_t *pHead = NULL;            // 封装包头

    // 参数校验
    if (NULL == pOut || NULL == pLen) {
        return -1;
    }

    pHead = (void *)pOut;
    // 封装包头
    pHead->ht_version = htons(_HT_VERSION);
    pHead->ht_len = htons(sizeof(ht_head_t));
    pHead->ht_type = htons(_HT_TYPE_HEARTBEAT);

    // 返回包长度
    *pLen = sizeof(ht_head_t);

    return 0;
}

// 数据报文封装
char *htprc_data(OUT char *pOut, OUT int *pLen, IN short type)
{
    int len = 0;
    ht_head_t *pHead = NULL;            // 封装包头

    // 参数校验
    if (NULL == pOut || NULL == pLen) {
        return NULL;
    }

    pHead = (void *)pOut - sizeof(ht_head_t);
    // 封装包头
    pHead->ht_version = htons(_HT_VERSION);
    pHead->ht_len = htons(sizeof(ht_head_t) + *pLen);
    pHead->ht_type = htons(type);

    // 返回包长度
    *pLen += sizeof(ht_head_t);

    return (void *)pHead;
}
